package com.zh.chat.net;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.BindException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

import net.sf.ezmorph.object.DateMorpher;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.JsonConfig;
import net.sf.json.util.CycleDetectionStrategy;
import net.sf.json.util.JSONUtils;

import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;

import com.zh.chat.entity.UDPProtocol;
import com.zh.chat.file.ConfigUtil;

/**
 * 网络服务类 一个socket用于收发命令 另一个socket用于检查用户是否在线
 * 
 * @author tom
 */
public class UDPNetDTOImpl extends DTOBase {
	private Logger log = Logger.getLogger(UDPNetDTOImpl.class);
	private Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
	private static JsonConfig jcfg = new JsonConfig();

	public UDPNetDTOImpl(ConfigUtil config) {
		super(config);
		init();
	}

	private void init() {
		
		try {
			this.inSocket = new DatagramSocket(serverRecvPort);// 监听端口
			this.outSocket = new DatagramSocket(serverSendPort);// 发送数据的端口
		} catch(BindException e1){
			log.error("端口被占用");
			return;
		} catch (SocketException e) {
			log.error(e);
		}
		jcfg.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
		jcfg.registerJsonValueProcessor("birthday", new DateJsonValueProcessor(
				dateFormat));
		jcfg.registerJsonValueProcessor("registerDate",
				new DateJsonValueProcessor(timeFormat));
		jcfg.registerJsonValueProcessor("lastLoginDate",
				new DateJsonValueProcessor(timeFormat));
	}

	public void close() {
		if (!inSocket.isClosed()) {
			inSocket.close();
			inSocket = null;
		}
		if (!outSocket.isClosed()) {
			outSocket.close();
			outSocket = null;
		}
	}

	public com.zh.chat.entity.UDPProtocol recive(){
		UDPProtocol prot = null;
		inBuf = new byte[MAX_PACKET_SIZE];
		DatagramPacket dp = new DatagramPacket(inBuf, MAX_PACKET_SIZE);// 设置udp缓冲区
		try {
			inSocket.receive(dp);
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 接收数据报
		int index = ArrayUtils.indexOf(inBuf, (byte) 0);// 找到字符串结尾
		inBuf = ArrayUtils.subarray(inBuf, 0, index);// 截取有用的字符串，删除后面的0
		if(inBuf.length==0){
			return null;
		}
		String jsonStr = null;
		try {
			jsonStr = new String(inBuf, CHARSET);
			log.info("接收"+jsonStr);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}// 得到json字符串
		
		JSONObject jsonObject = JSONObject.fromObject(jsonStr, jcfg);
		String clazz = (String) jsonObject.get("clazz");
		if(!clazz.equals("")){
			try {
				classMap.put("data", Class.forName((String) jsonObject.get("clazz")));
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		JSONUtils.getMorpherRegistry().registerMorpher(
				new DateMorpher(new String[] { timeFormat, dateFormat }));
		prot = (UDPProtocol) JSONObject.toBean(jsonObject, UDPProtocol.class,
				classMap);
		prot.setReciveTime(new java.util.Date().getTime());// 设置接收的时间
		if(prot.getCode() == UDPProtocol.REQ_IP){
			prot.setClientIp(dp.getAddress().getHostAddress());
		}
		return prot;
	}

	public void send(com.zh.chat.entity.UDPProtocol prot) throws IOException {
		Long targetId = prot.getRequestId();
		prot.setRequestId(prot.getTargetId());
		prot.setTargetId(targetId);
		prot.setServerIp(serverIp);
		prot.setServerPort(serverRecvPort);
		prot.setServerFilePort(TcpPort);
		prot.setSendTime(new java.util.Date().getTime());
		// JSONUtils.getMorpherRegistry().registerMorpher(new DateMorpher(new
		// String[]{"yyyy-MM-dd HH:mm:ss"}));
		jcfg.setExcludes(new String[]{"friendsesForSysId","friendsesForFriendId"});
		JSONObject o = (JSONObject) JSONSerializer.toJSON(prot, jcfg);
		String seri = o.toString();
		log.info("向"+prot.getClientIp()+":"+prot.getClientPort()+"发送"+seri);
		outBuf = seri.getBytes(CHARSET);// 编码方式UTF-8
		DatagramPacket dp = new DatagramPacket(outBuf, outBuf.length);
		dp.setAddress(InetAddress.getByName(prot.getClientIp()));
		dp.setPort(prot.getClientPort());// 设置此包的发送目的端口
		outSocket.send(dp);
	}
}